/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javamail.rtp;

import java.net.InetAddress;
import javax.media.MediaLocator;
import javax.media.control.BufferControl;
import javax.media.format.AudioFormat;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SessionAddress;
import javamail.sip.sipCall;

/**
 *
 * @author sriram
 */
public class rtp{
    private MediaLocator ml = null;
    private String localHost = null;
    private String remoteHost = null;
    private int localPort = 0;
    private int remotePort = 0;
    private AudioFormat[] fmt = null;
    private rtpTransmit transmitter = null;
    private rtpReceive receiver = null;
    private RTPManager mgr = null;
    private boolean receiverEnabled = false;
    private boolean transmitterEnabled = false;
    Object waitForEndOfRecording= new Object();


    public rtp(String lHost, int lPort,
                    String rHost, int rPort,
                    AudioFormat[] fmt)
    {
        this.localHost = lHost;
        this.localPort = lPort;
        this.remoteHost = rHost;
        this.remotePort = rPort;
        this.fmt = fmt;

        if(initManager(localHost, localPort, remoteHost, remotePort)) {

            // Create a audio transmit object with the specified params.
            // Try sending the current message if it exisits
            transmitter = new rtpTransmit(mgr, fmt);

            receiver = new rtpReceive(mgr, fmt);
            // Start receiving immediately after initializing
            // so as to not miss the NewReceiveStream event!
            if(startReceive()) {
                receiverEnabled = waitReceiveStart();
                //String result = null;
                //if((result=startTransmit())!=null) {
                //    System.err.println("Error occured while starting transmission: "+result);
                //}
            }
        } else {
            System.err.println("Error Occured: Unable to initialize RTP manager");
        }
    }

    public void run() {
        try {
            String result = null;
            // Start receiving immediately after initializing
            // so as to not miss the NewReceiveStream event!
            if(startReceive()) {
                waitReceiveStart();
            }
            // Then start the transmitter and send voice mail greeting
            // to the caller
            //if((result = startTransmit())!=null) {
                // In case the current message file does not exist, 
                // try sending the default message file.
            //    if(result.indexOf("Couldn't create DataSource")>=0 && ml!=null) {
            //        transmitter = new rtpTransmit(mgr, fmt);
            //        result = startTransmit();
            //    }
            //}
            if(result==null) {
                // Wait until Voice mail greeting is transmitted.
                // Greeting is the initial message from callee to caller
                scaleTransmission(4);
                waitForEndOfPlay();
                scaleTransmission(1);
                skipAbsolute(3);
                //if(transmitter.restartProcessor()==null);
                //    waitForEndOfPlay();

                // Start recording the caller's message now!
                //startRecording();

                // Start a timeout for a minute. The voice mail message
                // can be at a maximum of one minute in length
                waitForEndOfRecording();
            }
            else {
                System.err.println("Error Occured: "+result);
            }
        } catch(Exception e) {
            System.err.println(e.getMessage());
        } finally {
            // Stop processor and send BYE in case of any interrupts.
            stopRtpAndSendBye();
        }
    }

    // Either waits for a minute to end the recording and take down
    // the call OR will be interrupted by sipCall when a BYE comes in
    // to take down the call and stop RTP transreceive
    public void waitForEndOfRecording(){
	synchronized (waitForEndOfRecording) {
            try {
            waitForEndOfRecording.wait(20000);
            } catch (InterruptedException e) {}
	}
	return;
    }

    public void stopRtp() {
        //System.err.println("rtp:stopRtp()-In function");
        synchronized(waitForEndOfRecording) {
            waitForEndOfRecording.notifyAll();
        }
        stopTransmit();
        stopReceive();
        //System.err.println("rtp:stopRtp()-After stopping transreceive");
        closeManager();
    }
    public void stopRtpAndSendBye() {
        stopTransmit();
        stopReceive();
        closeManager();
        //synchronized(call) {
        //    call.sendBye();
        //}
    }
    
    public String startTransmit(MediaLocator ml) {
        String result = "Transmitter object null";
    	// Start the transmission
        if(transmitter!=null) {
            result = transmitter.start();
            transmitter.setLocator(ml);
        }
        return result;
    }
    public String startPlaying() {
        if(transmitter!=null)
            return transmitter.startPlaying();
        return null;
    }
    public String stopPlaying() {
        if(transmitter!=null)
            return transmitter.stopPlaying();
        return null;
    }
    public void waitForEndOfPlay() {
        if(transmitter!=null)
            transmitter.waitForEndOfMedia();
    }
    public void scaleTransmission(int rate) {
        if(transmitter!=null) {
            String result = transmitter.setProcessorRate(rate);
            System.err.println("rtpThread:scaleTransmission()- Result: "+result);
        }
    }
    public void skipRelative(int time) {
        if(transmitter!=null) {
            String result = transmitter.jumpProcessorTime(time);
            System.err.println("rtpThread:skipForwardTransmission()- Result: "+result);
        }
    }
    public void skipAbsolute(int time) {
        if(transmitter!=null) {
            String result = transmitter.setProcessorTime(time);
            System.err.println("rtpThread:skipForwardAbsTransmission()- Result: "+result);
        }
    }
    public void stopTransmit() {
        if(transmitter!=null) {
            //System.err.println("rtp:stopTransmit()-In function");
            transmitter.stop();
        }
    }
    public boolean startReceive() {
        boolean result = false;
    	// Start the reception
        if(receiver!=null) {
            result = receiver.initialize();
        }
        return result;
    }
    public boolean waitReceiveStart() {
        boolean result = false;
        if(receiver!=null)
            result = receiver.waitForReceptionStart();
        return result;
    }
    public void startRecording(MediaLocator ml) {
        if(receiver!=null) {
            receiver.setLocator(ml);
            receiver.startRecording();
        }
    }
    public void stopRecording() {
        if(receiver!=null) {
            synchronized(waitForEndOfRecording) {
                waitForEndOfRecording.notifyAll();
            }
           receiver.stopRecording();
        }
    }
    public void stopReceive() {
        if(receiver!=null) {
            //System.err.println("rtp:stopReceive()-In function");
            receiver.close();
        }
    }
    public boolean initManager(String localHost, int localPort, String remoteHost, int remotePort) {
        try {
	    SessionAddress localAddr = null;
	    SessionAddress destAddr = null;
            InetAddress localIp = null, remoteIp = null;

	    mgr = (RTPManager) RTPManager.newInstance();

            localIp = InetAddress.getByName(localHost);
            localIp = InetAddress.getLocalHost();
            remoteIp = InetAddress.getByName(remoteHost);

            // Open the RTP sessions.
            System.err.println(" - Open RTP session for: Local addr: " + localIp + " port: " + localPort);
            System.err.println(" - Open RTP session for: Remote addr: " + remoteIp + " port: " + remotePort);

            localAddr= new SessionAddress( localIp, localPort);
            destAddr = new SessionAddress( remoteIp, remotePort);

            mgr.initialize( localAddr);

            // You can try out some other buffer size to see
            // if you can get better smoothness.
            BufferControl bc = (BufferControl)mgr.getControl("javax.media.control.BufferControl");
            if (bc != null)
                bc.setBufferLength(640);

            mgr.addTarget(destAddr);
            return true;
        } catch (Exception e){
            System.err.println("Cannot create the RTP Session: " + e.getMessage());
            return false;
        }
    }

     public void closeManager() {
        //System.err.println("rtp:closeManager()- Closing RTP manager and streams!");
        try {
            if(mgr!=null) {
                mgr.removeTargets("Session ended.");
                mgr.dispose();
                mgr = null;
            }
        } catch (Exception e) {}
    }

    String getIpFromString(String ipaddr) {
        String result = null;
        int off = 0;

        off = ipaddr.indexOf("/");
        result = ipaddr.substring(off+1);
        return result;
    }

}
